home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / comm / mail / YAM23src.lha / Source / YAM_MI.c < prev    next >
C/C++ Source or Header  |  2001-05-08  |  17KB  |  626 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 1995-2000 by Marcel Beck <mbeck@yam.ch>
  5.  Copyright (C) 2000-2001 by YAM Open Source Team
  6.  
  7.  This program is free software; you can redistribute it and/or modify
  8.  it under the terms of the GNU General Public License as published by
  9.  the Free Software Foundation; either version 2 of the License, or
  10.  (at your option) any later version.
  11.  
  12.  This program is distributed in the hope that it will be useful,
  13.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  GNU General Public License for more details.
  16.  
  17.  You should have received a copy of the GNU General Public License
  18.  along with this program; if not, write to the Free Software
  19.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  
  21.  YAM Official Support Site :  http://www.yam.ch
  22.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  23.  
  24.  $Id: YAM_MI.c,v 1.6 2001/05/08 22:27:37 damato Exp $
  25.  
  26. ***************************************************************************/
  27.  
  28. #include "YAM.h"
  29.  
  30. /* local */
  31. LOCAL int nextcharin(FILE*, BOOL);
  32. LOCAL void output64chunk(int, int, int, int, FILE*);
  33. LOCAL void almostputc(int, FILE*, struct TranslationTable*, BOOL);
  34. LOCAL void uueget(char*, FILE*, int);
  35. LOCAL BOOL gettxtline(char*, int, char**);
  36. LOCAL BOOL getline(char*, int, FILE*);
  37. LOCAL int outdec(char*, FILE*);
  38.  
  39.  
  40. /***************************************************************************
  41.  MIME I/O routines
  42. ***************************************************************************/
  43.  
  44. /// Global variables
  45. static char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  46. static char basis_hex[] = "0123456789ABCDEF";
  47.  
  48. static char index_64[128] = {
  49.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  50.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  51.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
  52.    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
  53.    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
  54.    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
  55.    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
  56.    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
  57. };
  58. static char index_hex[128] = {
  59.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  60.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  61.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  62.     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,
  63.    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  64.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  65.    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  66.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
  67. };
  68.  
  69. #define hexchar(c)  (((c) > 127) ? -1 : index_hex[(c)])
  70. #define char64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
  71. #define SUMSIZE 64
  72. #define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
  73.  
  74. static BOOL InNewline = FALSE;
  75. static BOOL CRpending = FALSE;
  76. BOOL *NeedsPortableNewlines;
  77. ///
  78.  
  79. /// nextcharin
  80. //  Reads next byte from a text files, handles CRLF line breaks
  81. LOCAL int nextcharin(FILE *infile, BOOL PortableNewlines)
  82. {
  83.    int c;
  84.  
  85.    if (!PortableNewlines) return fgetc(infile);
  86.    if (InNewline) { InNewline = FALSE; return 10; }    /***BUG***/
  87.    c = fgetc(infile);
  88.    if (c == '\n') { InNewline = TRUE; return 13; }
  89.    return c;
  90. }
  91.  
  92. ///
  93. /// encode64
  94. //  Encodes string in base64 format
  95. void encode64(char *s, char *d, int len)
  96. {
  97.    int i;
  98.  
  99.    for(i=0;i<len;i+=3)
  100.    {
  101.       int c1, c2, c3, c4, count=len-i;
  102.  
  103.       c1 = *s >> 2;
  104.       c2 = ((*s << 4) & 060) | ((s[1] >> 4) & 017);
  105.       c3 = ((s[1] << 2) & 074) | ((s[2] >> 6) & 03);
  106.       c4 = s[2] & 077;
  107.       *d++=basis_64[c1];
  108.       *d++=basis_64[c2];
  109.       if (count == 1) {
  110.      *d++='=';
  111.      *d++='=';
  112.       } else {
  113.       *d++=basis_64[c3];
  114.       if (count == 2)
  115.               *d++='=';
  116.       else
  117.           *d++=basis_64[c4];
  118.       }
  119.       s+=3;
  120.    }
  121.    *d=0;
  122. }
  123.  
  124. ///
  125. /// decode64
  126. //  Decodes string in base64 format
  127. #define BASE64(c) (index_64[(unsigned char)(c) & 0x7F])
  128. char *decode64 (char *dest, char *src, char *srcmax)
  129. {
  130.    while (src + 3 < srcmax)
  131.      {
  132.     *dest++ = (BASE64(src[0]) << 2) | (BASE64(src[1]) >> 4);
  133.     
  134.     if (src[2] == '=') break;
  135.     *dest++ = ((BASE64(src[1]) & 0xf) << 4) | (BASE64(src[2]) >> 2);
  136.     
  137.     if (src[3] == '=') break;
  138.     *dest++ = ((BASE64(src[2]) & 0x3) << 6) | BASE64(src[3]);
  139.     src += 4;
  140.      }
  141.    *dest=0;
  142.    return dest;
  143. }
  144. ///
  145. /// output64chunk
  146. //  Writes three bytes in base64 format
  147. LOCAL void output64chunk(int c1, int c2, int c3, int pads, FILE *outfile)
  148. {
  149.    fputc(basis_64[c1>>2], outfile);
  150.    fputc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
  151.     switch(pads)
  152.     {
  153.        case 0 :
  154.           fputc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
  155.           fputc(basis_64[c3 & 0x3F], outfile);
  156.           break;
  157.         case 2 :
  158.           fputs("==", outfile);
  159.             break;
  160.         default :
  161.           fputc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
  162.           fputc('=', outfile);
  163.    }
  164. /*
  165.    if (pads == 2) 
  166.    {
  167.       fputs("==", outfile);
  168.    } 
  169.    else if (pads) 
  170.    {
  171.       fputc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
  172.       fputc('=', outfile);
  173.    }
  174.    else 
  175.    {
  176.       fputc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
  177.       fputc(basis_64[c3 & 0x3F], outfile);
  178.    }
  179. */
  180. }
  181.  
  182. ///
  183. /// to64
  184. //  Encodes a file using base64 format
  185. void to64(FILE *infile, FILE *outfile, BOOL PortableNewlines)
  186. {
  187.    int c1, c2, c3, ct=0;
  188.    InNewline = 0;
  189.    while ((c1 = nextcharin(infile, PortableNewlines)) != -1)
  190.    {
  191.       c2 = nextcharin(infile, PortableNewlines);
  192.       if (c2 == -1)
  193.          output64chunk(c1, 0, 0, 2, outfile);
  194.       else
  195.       {
  196.          c3 = nextcharin(infile, PortableNewlines);
  197.          if (c3 == -1) output64chunk(c1, c2, 0, 1, outfile);
  198.          else          output64chunk(c1, c2, c3, 0, outfile);
  199.       }
  200.       ct += 4;
  201.       if (ct > 71) { fputc('\n', outfile); ct = 0; }
  202.    }
  203.    if (ct) fputc('\n', outfile);
  204. }
  205.  
  206. ///
  207. /// almostputc
  208. //  Writes a bytes, handles line breaks and translation tables
  209. LOCAL void almostputc(int c, FILE *outfile, struct TranslationTable *tt, BOOL PortableNewlines)
  210. {
  211.    if (tt) c = (int)tt->Table[(UBYTE)c];
  212.    if (CRpending) 
  213.    {
  214.       if (c == 10) { fputc('\n', outfile); CRpending = FALSE; }
  215.       else
  216.       {
  217.          fputc(13, outfile);
  218.          if (c != 13) { fputc(c, outfile); CRpending = FALSE; }
  219.       }
  220.    } 
  221.    else 
  222.       if (PortableNewlines && c == 13) CRpending = TRUE; else fputc(c, outfile);
  223. }
  224.  
  225. ///
  226. /// from64txt
  227. //  Decodes a string in base64 format
  228. void from64txt(char *src, char *dst, struct TranslationTable *tt)
  229. {
  230.    int c1, c2, c3, c4;
  231.    UBYTE c;
  232.  
  233.    while (c1 = (int)*src++)
  234.    {
  235.       if (ISpace((char)c1)) continue;
  236.       do { c2 = (int)*src++; } while (c2 && ISpace((char)c2));
  237.       do { c3 = (int)*src++; } while (c3 && ISpace((char)c3));
  238.       do { c4 = (int)*src++; } while (c4 && ISpace((char)c4));
  239.       if (!c2 || !c3 || !c4) return;
  240.       c1 = char64(c1); c2 = char64(c2); c = (UBYTE)((c1<<2) | ((c2&0x30)>>4));
  241.       *dst++ = tt ? (char)tt->Table[c] : (char)c;
  242.       if (c3 != '=') 
  243.       {
  244.          c3 = char64(c3); c = (UBYTE)(((c2&0XF) << 4) | ((c3&0x3C) >> 2));
  245.          *dst++ = tt ? (char)tt->Table[c] : (char)c;
  246.          if (c4 != '=') 
  247.          {
  248.             c4 = char64(c4); c = (UBYTE)(((c3&0x03) <<6) | c4);
  249.             *dst++ = tt ? (char)tt->Table[c] : (char)c;
  250.          }
  251.       }
  252.    }
  253. }
  254.  
  255. ///
  256. /// from64
  257. //  Decodes a file in base64 format
  258. void from64(FILE *infile, FILE *outfile, struct TranslationTable *tt, BOOL PortableNewlines)
  259. {
  260.    int c1, c2, c3, c4;
  261.    BOOL DataDone = FALSE;
  262.  
  263.    CRpending = FALSE;
  264.    while ((c1 = fgetc(infile)) != -1) 
  265.    {
  266.       if (ISpace((char)c1)) continue;
  267.       if (DataDone) continue;
  268.       do { c2 = fgetc(infile); } while (c2 != -1 && ISpace((char)c2));
  269.       do { c3 = fgetc(infile); } while (c3 != -1 && ISpace((char)c3));
  270.       do { c4 = fgetc(infile); } while (c4 != -1 && ISpace((char)c4));
  271.       if (c2 == -1 || c3 == -1 || c4 == -1) 
  272.       {
  273.          ER_NewError(GetStr(MSG_ER_UnexpEOFB64), NULL, NULL);
  274.          return;
  275.       }
  276.       if (c1 == '=' || c2 == '=') { DataDone = TRUE; continue; }
  277.       c1 = char64(c1);
  278.       c2 = char64(c2);
  279.       almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, tt, PortableNewlines);
  280.       if (c3 == '=') 
  281.          DataDone = TRUE;
  282.       else 
  283.       {
  284.          c3 = char64(c3);
  285.          almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, tt, PortableNewlines);
  286.          if (c4 == '=') 
  287.             DataDone = 1;
  288.          else  
  289.          {
  290.             c4 = char64(c4);
  291.             almostputc((((c3&0x03) <<6) | c4), outfile, tt, PortableNewlines);
  292.          }
  293.       }
  294.    }
  295.    if (CRpending) fputc(13, outfile);
  296. }
  297.  
  298. ///
  299. /// toqp
  300. //  Encodes a file using quoted-printable format
  301. void toqp(FILE *infile, FILE *outfile)
  302. {
  303.    int c, ct = 0, prevc = 255;
  304.  
  305.    while ((c = fgetc(infile)) != -1)
  306.    {
  307.       if ((c < 32 && (c != '\n' && c != '\t')) || (c == '=') || (c >= 127) || (ct == 0 && c == '.')) 
  308.       {
  309.          fputc('=', outfile);
  310.          fputc(basis_hex[c>>4], outfile);
  311.          fputc(basis_hex[c&0xF], outfile);
  312.          ct += 3;
  313.          prevc = 'A';
  314.       }
  315.       else if (c == '\n') 
  316.       {
  317.          if (prevc == ' ' || prevc == '\t') 
  318.          {
  319.             fputs("=\n", outfile);
  320.          }
  321.          fputc('\n', outfile);
  322.          ct = 0;
  323.          prevc = c;
  324.       } 
  325.       else 
  326.       {
  327.          if (c == 'F' && prevc == '\n') 
  328.          {
  329.             if ((c = fgetc(infile)) == 'r') 
  330.                if ((c = fgetc(infile)) == 'o') 
  331.                   if ((c = fgetc(infile)) == 'm') 
  332.                      if ((c = fgetc(infile)) == ' ') { fputs("=46rom", outfile);  ct += 6; }
  333.                      else { fputs("From", outfile); ct += 4; }
  334.                   else { fputs("Fro", outfile); ct += 3; }
  335.                else { fputs("Fr", outfile); ct += 2; }
  336.             else { fputc('F', outfile); ++ct; }
  337.             ungetc(c, infile);
  338.             prevc = 'x'; 
  339.          } 
  340.          else
  341.          {
  342.             fputc(c, outfile);
  343.             ++ct;
  344.             prevc = c;
  345.          }
  346.       }
  347.       if (ct > 72) 
  348.       {
  349.          fputs("=\n", outfile);
  350.          ct = 0;
  351.          prevc = '\n';
  352.       }
  353.    }
  354.    if (ct) fputs("=\n", outfile);
  355. }
  356.  
  357. ///
  358. /// fromform
  359. //  Converts an url-encoded file into plain text
  360. void fromform(FILE *infile, FILE *outfile, struct TranslationTable *tt)
  361. {
  362.    unsigned int c;
  363.    while ((c = fgetc(infile)) != -1)
  364.    {
  365.       switch (c)
  366.       {
  367.          case '&': fputc('\n', outfile); break;
  368.          case '%': c = (index_hex[fgetc(infile)]<<4)+index_hex[fgetc(infile)];
  369.                    switch (c)
  370.                    {
  371.                       case '\n': fputs("\n ", outfile); break;
  372.                       case '\r': break;
  373.                       default  : fputc(tt ? (int)tt->Table[(UBYTE)c] : c, outfile); break;
  374.                    }
  375.                    break;
  376.          case '+': fputc(' ', outfile); break;
  377.          case '=': fputs(" = ", outfile); break;
  378.          default : fputc(tt ? (int)tt->Table[(UBYTE)c] : c, outfile); break;
  379.       }
  380.    }
  381. }
  382.  
  383. ///
  384. /// fromqptxt
  385. //  Decodes a string in quoted-printable format
  386. void fromqptxt(char *src, char *dst, struct TranslationTable *tt)
  387. {
  388.    unsigned int c1, c2;
  389.    UBYTE c;
  390.  
  391.    while (c1 = *src++) 
  392.       if (c1 == '=') 
  393.       {
  394.          c1 = *src++; c2 = *src++;
  395.          c1 = hexchar(c1); c2 = hexchar(c2); c = (UBYTE)(c1<<4 | c2);
  396.          *dst++ = tt ? (char)tt->Table[c] : (char)c;
  397.       }
  398.       else *dst++ = tt ? (char)tt->Table[(UBYTE)c1] : (char)c1;
  399. }
  400.  
  401. ///
  402. /// fromqp
  403. //  Decodes a file in quoted-printable format
  404. void fromqp(FILE *infile, FILE *outfile, struct TranslationTable *tt)
  405. {
  406.    unsigned int c1, c2;
  407.    BOOL neednewline = FALSE;
  408.  
  409.    while ((c1 = fgetc(infile)) != -1) 
  410.    {
  411.       if (neednewline) { fputc('\n', outfile); neednewline = FALSE; };
  412.       if (c1 == '=')
  413.       {
  414.          c1 = fgetc(infile);
  415.          if (c1 != '\n')
  416.          {
  417.             c2 = fgetc(infile);
  418.             c1 = hexchar(c1);
  419.             c2 = hexchar(c2);
  420.             fputc(tt ? (int)tt->Table[(UBYTE)(c1<<4 | c2)] : c1<<4 | c2, outfile);
  421.          }
  422.       }
  423.       else if (c1 == '\n') neednewline = TRUE;
  424.       else fputc(tt ? (int)tt->Table[(UBYTE)c1] : c1, outfile);
  425.    }
  426.    if (neednewline) fputc('\n', outfile);
  427. }
  428.  
  429. ///
  430. /// DoesNeedPortableNewlines
  431. //  Checks if line breaks must be portable (CRLF)
  432. BOOL DoesNeedPortableNewlines(char *ctype)
  433. {
  434.    if (!strnicmp(ctype, "text", 4)) return TRUE;
  435.    if (!strnicmp(ctype, "message", 7)) return TRUE;
  436.    if (!strnicmp(ctype, "multipart", 9)) return TRUE;
  437.    return FALSE;
  438. }
  439. ///
  440.  
  441. /*** UU encode/decode stuff ***/
  442. /// uueget
  443. //  Decodes four UU encoded bytes
  444. LOCAL void uueget(char *ptr, FILE *outfp, int n)
  445. {
  446.    int c1, c2, c3;
  447.    unsigned char p0, p1, p2, p3;
  448.  
  449.    p0 = (ptr[0] - ' ') & 0x3F;
  450.    p1 = (ptr[1] - ' ') & 0x3F;
  451.    p2 = (ptr[2] - ' ') & 0x3F;
  452.    p3 = (ptr[3] - ' ') & 0x3F;
  453.    c1 = p0 << 2 | p1 >> 4;
  454.    c2 = p1 << 4 | p2 >> 2;
  455.    c3 = p2 << 6 | p3;
  456.    if (n >= 1) fputc(c1, outfp);
  457.    if (n >= 2) fputc(c2, outfp);
  458.    if (n >= 3) fputc(c3, outfp);
  459. }
  460.  
  461. ///
  462. /// gettxtline
  463. //  Reads next line of UU encoded string
  464. LOCAL BOOL gettxtline(char *buf, int size, char **rptr)
  465. {
  466.    int c;
  467.    char *ptr = buf;
  468.  
  469.    for (c = 0; c < size; ++c)buf[c] = ' ';
  470.    do 
  471.    {
  472.       c = (int)**rptr; (*rptr)++;
  473.       if (!c) { *ptr = '\0'; return (BOOL)(ptr == buf); }
  474.       else if (c == '\n' || c == '\r') { *ptr = '\0'; return False; }
  475.     // Emm: I guess the following line was meant to process quoted
  476.     // mails, but it causes file corruption when the '>' is really
  477.     // part of the uuencoding (usually, this happens for the last
  478.     // line).
  479.       //else if (ptr == buf && c == '>') continue;
  480.       else if (size > 0) { *ptr++ = c; size--; }
  481.    } while (TRUE);
  482.    return False;
  483. }
  484.  
  485. ///
  486. /// fromuuetxt
  487. //  Decodes a string in UUE format
  488. void fromuuetxt(char **txt, FILE *outfp)
  489. {
  490.    char buf[SIZE_LINE];
  491.  
  492.    while (TRUE)
  493.    {
  494.       if (gettxtline(buf, sizeof(buf), txt)) 
  495.       {
  496.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  497.          return;
  498.       }        
  499.       if (!strncmp(buf, "begin", 5)) break;
  500.    }  
  501.    while (TRUE) 
  502.    {
  503.       if (gettxtline(buf, sizeof(buf), txt)) 
  504.       {
  505.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  506.          return;
  507.       }        
  508.       else if (!strncmp(buf, "end", 5)) break;
  509.       else if (*buf == '\0') continue;
  510.       else 
  511.       {
  512.          int length = (*buf - ' ');
  513.          if (*buf == '`') length = 0;
  514.          if (length < 0 || length > 63) 
  515.             ER_NewError(GetStr(MSG_ER_InvalidLength), (char *)length, NULL);
  516.          else 
  517.          {
  518.             char *ptr = buf + 1;
  519.             while (length > 0) { uueget(ptr, outfp, length); length -= 3; ptr += 4; }
  520.          }
  521.       }
  522.    }
  523. }
  524.  
  525. ///
  526. /// getline
  527. //  Reads next line from a UU encoded file
  528. LOCAL BOOL getline(char *buf, int size, FILE *fp)
  529. {
  530.    int c;
  531.    char *ptr = buf;
  532.  
  533.    for (c = 0; c < size; ++c)buf[c] = ' ';
  534.    do 
  535.    {
  536.       if ((c = fgetc(fp)) == -1) {*ptr = '\0'; return (BOOL)(ptr == buf); }
  537.       else if (c == '\n' || c == '\r') { *ptr = '\0'; return False; }
  538.     // Emm: I guess the following line was meant to process quoted
  539.     // mails, but it causes file corruption when the '>' is really
  540.     // part of the uuencoding (usually, this happens for the last
  541.     // line).
  542.       //else if (ptr == buf && c == '>') continue;
  543.       else if (size > 0) { *ptr++ = c; size--; }
  544.    } while (TRUE);
  545.    return False;
  546. }
  547.  
  548. ///
  549. /// fromuue
  550. //  Decodes a file in UUE format
  551. void fromuue(FILE *infp, FILE *outfp)
  552. {
  553.    char buf[SIZE_LINE];
  554.  
  555.    while (TRUE) 
  556.    {
  557.       if (getline(buf, sizeof(buf), infp)) 
  558.       {
  559.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  560.          return;
  561.       }        
  562.       if (!strncmp(buf, "begin", 5)) break;
  563.    }  
  564.    while (TRUE) 
  565.    {
  566.       if (getline(buf, sizeof(buf), infp)) 
  567.       {
  568.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  569.          return;
  570.       }        
  571.       else if (!strncmp(buf, "end", 5)) break;
  572.       else if (*buf == '\0') continue;
  573.       else 
  574.       {
  575.          int length = (*buf - ' ');
  576.          if (*buf == '`') length = 0;
  577.          if (length < 0 || length > 63) 
  578.             ER_NewError(GetStr(MSG_ER_InvalidLength), (char *)length, NULL);
  579.          else 
  580.          {
  581.             char *ptr = buf + 1;
  582.             while (length > 0) { uueget(ptr, outfp, length); length -= 3; ptr += 4; }
  583.          }
  584.       }
  585.    }
  586. }
  587.  
  588. ///
  589. /// outdec
  590. //  Encodes three bytes using UUE format
  591. LOCAL int outdec(char *p, FILE *out)
  592. {
  593.    int c1,c2,c3,c4;
  594.  
  595.    c1 = *p >> 2;
  596.    c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
  597.    c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
  598.    c4 = p[2] & 077;
  599.    fputc(ENC(c1), out);
  600.    fputc(ENC(c2), out);
  601.    fputc(ENC(c3), out);
  602.    fputc(ENC(c4), out);
  603.    return (p[0]+p[1]+p[2]) % SUMSIZE;
  604. }
  605.  
  606. ///
  607. /// touue
  608. //  Encodes a file using UUE format
  609. void touue(FILE *in, FILE *out)
  610. {
  611.    char buf[80];
  612.    int i,n,checksum;
  613.  
  614.    for (;;) 
  615.    {
  616.       n = fread(buf, 1, 45, in);
  617.       fputc(ENC(n), out);
  618.       checksum = 0;
  619.       for (i = 0; i < n; i += 3) checksum = (checksum+outdec(&buf[i], out))%SUMSIZE;
  620.       fputc(ENC(checksum), out);
  621.       fputc('\n', out);
  622.       if (n <= 0) break;
  623.    }
  624. }
  625. ///
  626.